/*
 * pmod_clp.c
 *
 *  Created on: Mar 12, 2015
 *  Author:		Abhishek Malik
 *
 * This is my honest attempt at writing a thread safe driver for the PMOD-CLP
 * This is the high/low level driver for the PMODCLP (LCD 16x2).
 * it provides a small API for the user to write to the LCD. it also takes care of the
 * initialization of the LCD. This API is very small and doesn't accomplish everything
 * however it accomplishes just enough as required for the project.
 */

#include "pmod_clp.h"

/**
 * This is the initialization function used to initialize the LCD or PMOD-CLP.
 * It follows the basic initialization sequence as provided in the datasheet.
 * it doesnt follow the exact timing sequence however. It overshoots the time by quite a bit
 * however it still gets done within 150 ms so its still pretty quick for the human eye.
 *
 * @param: an instance of XGpio (GPIO)
 */
void init_lcd(XGpio * InstPtr){
	// giving it initial time to start up
	sleep(100);
	// function set
	lcd_write(InstPtr, 0x38);
	sleep(5);
	// giving function set again just to be careful
	lcd_write(InstPtr, 0x38);
	sleep(5);
	// display set
	lcd_write(InstPtr, 0x0c);
	sleep(5);
	// set the entry mode
	lcd_write(InstPtr, 0x06);
	sleep(5);
	// clear the display
	lcd_write(InstPtr, 0x01);
	sleep(2);
	// the LCD is now ready to be written to
}

/**
 * This function is used to write to the LCD, since the enable signal has to be toggled
 * everytime the LCD is being written to, this function takes care of that
 *
 * @param: an instance of XGpio (GPIO)
 * @param: data to be written to the LCD
 */
void lcd_write(XGpio * InstPtr, int dat){
	// set the enable signal high
	int enable_dat = dat|0x100;
	// sleep is important here so that the writing takes place properly
	sleep(2);
	XGpio_DiscreteWrite(InstPtr, 1, dat);			// put the data on the bus
	XGpio_DiscreteWrite(InstPtr, 1, enable_dat);	// Enable: HI->LO
	XGpio_DiscreteWrite(InstPtr, 1, enable_dat);	// Enable: HI->LO
	XGpio_DiscreteWrite(InstPtr, 1, dat);			// Enable: LO->HI
}

/**
 * this function is used to write a string to the LCD screen.
 * The parameters that the user passes do the following:
 *
 * 1. InstPtr -  	a GPIO instance pointer
 * 2. string -   	character array to be written on the LCD
 * 3. line_no -  	which line to write on in the LCD
 * 4. start_pt - 	starting from this location on the given line
 */
void lcd_write_string(XGpio * InstPtr, char* string, int line_no, int start_pt){
	// declaring variables for the function
	int index = 0;
	int stringASCII;
	// you cant start writing after the 8th location in any of the lines
	// thats only for starting after the 8th location, if you've started before you can continue
	// upto the end. No real reason for this, just wanted to include it as a safety measure
	if(start_pt>8){
		start_pt = 8;
	}
	if(line_no==2){
		// moving the cursor to the second line
		lcd_write(InstPtr, 0xC0|start_pt);
	}
	else{
		// cursor on the first line and at the start point
		lcd_write(InstPtr, 0x80|start_pt);
	}

	// writing a string to the LCD
	// since the characters are already somehow mapped to their ASCII values in the LCD
	// you just need to convert the character to an int and send it to the LCD which would
	// display the characters on the LCD
	while(string[index]!='\0'){
		// convert the character to an ASCII value to be written on the screen
		stringASCII =string[index];
		// moving on the next character
		index++;
		// setting the appropriate value of RS and RW signals
		stringASCII |= 0x400;
		// write to the LCD
		lcd_write(InstPtr, stringASCII);
	}
}

/**
 * this function is used to clear the LCD screen
 */
void lcd_cls(XGpio * InstPtr){
	lcd_write(InstPtr, LCD_CLS_INST);
}

/**
 * this function is used to write a decimal to the LCD screen.
 * The parameters that the user passes do the following:
 *
 * 1. InstPtr -  	a GPIO instance pointer
 * 2. num -   		an integer to be written on the LCD
 * 3. line_no -  	which line to write on in the LCD
 * 4. cursor_loc -  starting from this location on the given line
 */
void lcd_write_decimal(XGpio * InstPtr, int num, int cursor_loc, int line_no){
	// declaring the variables to be used by the function
	int num_arr[5];
	int num_to_print;
	int index_num=0;
	// splitting up the decimal number and putting it in an array
	while(num!=0){
		num_arr[index_num] = num%10;
		num=num/10;
		index_num++;
	}
	index_num--;
	// setting the cursor to the appropriate line and location
	if(line_no==2){
		lcd_write(InstPtr, 0xC0|cursor_loc);
	}
	else{
		lcd_write(InstPtr, 0x80|cursor_loc);
	}
	// writing the number to the LCD location
	while(index_num>=0){
		num_to_print = 0x430|num_arr[index_num];
		lcd_write(InstPtr, num_to_print);
		index_num--;
	}
}
